package parser

import scala.util.parsing.combinator._
import scala.collection.mutable.ArrayBuffer
import ewu._

/**
 * Die Klasse WhileParser bietet Funktionen zum umwandeln eines uebergebenen
 * String in WHILE-Sprache in die interne EWU-Struktur.
 */

class WhileParser extends JavaTokenParsers {
  //Parser fuer Zusicherungen
  def Zusicherung: Parser[Assertion] = "{" ~> ident ~ ":" ~ Bedingungen <~ "}" ^^ { 
                                          case i~":"~b => Assertion(i,b)}
  
  //Parser fuer Quell-Code, liefert Anweisungsfolge
  def AnwfolgeK: Parser[Anweisungsfolge] = Anwfolge ^^ {x => Anweisungsfolge(x)}
  def Anwfolge: Parser[ArrayBuffer[Anweisung]] = rep(Anw) ^^ {ArrayBuffer[Anweisung]() ++ _}
  
  def Anw: Parser[Anweisung] = AFall | ASchleife | Zusicherung | AZuweisung
  def AFall: Parser[Fall] = "if" ~> Bedingungen ~ "then" ~ AnwfolgeK <~ "fi" ^^ {
                                case b ~ "then" ~ a => null
                              } |
                            "if" ~> Bedingungen ~ "then" ~ AnwfolgeK ~ "else" ~ 
                            AnwfolgeK <~ "fi" ^^ {
                                case b ~ "then" ~ a ~ "else" ~ a2 => null 
                              } 
  def ASchleife: Parser[Schleife] = "while" ~> Bedingungen ~ "do" ~ AnwfolgeK <~ "od" ^^ { 
                                        case b ~ "do" ~ a => Schleife(b,a)}
  
  def Bedingungen: Parser[BoolExpression] = ("!(" ~> Bedingungen <~ ")" | "!" ~> Bedingung) ^^ 
                                                { b => Not(b)} |
                                            "(" ~> Bedingungen ~ ")" ~ "and" ~ Bedingungen ^^ 
                                                { case b1~")"~"and"~b2 => AND(b1,b2)} |
                                            "(" ~> Bedingungen ~ ")" ~ "or" ~ Bedingungen ^^ 
                                                { case b1~")"~"or"~b2 => OR(b1,b2)} |
                                            "(" ~> Bedingungen <~ ")" |
                                            Bedingung ~ "and" ~ Bedingungen ^^ 
                                                { case b1~"and"~b2 => AND(b1,b2)} |
                                            Bedingung ~ "or" ~ Bedingungen ^^ 
                                                { case b1~"or"~b2 => OR(b1,b2)} |
                                            Bedingung
  
  def Bedingung: Parser[Comparison] = Ausdruck ~ VergleichOp ~ Ausdruck ^^ {
                                case a1~">="~a2 => GOE(a1,a2)
                                case a1~"<="~a2 => LOE(a1,a2)
                                case a1~"=="~a2 => Equal(a1,a2)
                                case a1~"!="~a2 => Unequal(a1,a2)
                                case a1~">"~a2 => Greater(a1,a2)
                                case a1~"<"~a2 => Lesser(a1,a2)
                                case a1~"="~a2 => Equal(a1,a2)
                              }
  def VergleichOp: Parser[Any] = ">=" | "<=" | "==" | "!=" | "<" | ">" | "="
  def Skip: Parser[Any] = ""
  def AZuweisung: Parser[Zuweisung] =  ident ~ ":=" ~ Ausdruck <~ ";" ^^ 
                                            { case i ~ ":=" ~ a => Zuweisung(i,a)}
  
  def Ausdruck: Parser[Expression] = programmitems ~ Op ~ Ausdruck ^^ {
                                case a1~"+"~a2 => Plus(a1,a2)
                                case a1~"-"~a2 => Minus(a1,a2)
                                case a1~"*"~a2 => Mult(a1,a2)
                                case a1~"/"~a2 => Div(a1,a2)
                              } | "(" ~> Ausdruck ~ ")" ~ Op ~ Ausdruck ^^ {
                                case a1~")"~"+"~a2 => Plus(a1,a2)
                                case a1~")"~"-"~a2 => Minus(a1,a2)
                                case a1~")"~"*"~a2 => Mult(a1,a2)
                                case a1~")"~"/"~a2 => Div(a1,a2)
                              } | "(" ~> Ausdruck <~ ")" | programmitems
  def Op: Parser[Any] = "+" | "-" | "*" | "/"
  
  def programmitems: Parser[Expression] = wholeNumber ^^ {n => Number(n.toInt)} | 
                              //decimalNumber ^^ {n => Number(n.toInt)} | 
                              ident ^^ {n => Name(n)} |
                              "-" ~> ident ^^ {n => Minus(Number(0),Name(n))}
                              
  def boolean: Parser[BoolExpression] = "true" ^^^ {new True} | "false" ^^^ {new False}

}

object ParseWhile extends WhileParser  {  
  def par(arg: String) : Anweisungsfolge = {
    var tmp:Anweisungsfolge = parseAll(AnwfolgeK, arg) match {
        case Success(anwf,_) => anwf
        case NoSuccess(msg,_) => null
    }
    return tmp
  }
  def parError(arg: String) : (String, Int, Int) = {
    var tmp = parseAll(AnwfolgeK, arg) match {
        case Success(anwf,_) => ("OK", 0, 0)
        case NoSuccess(msg,str) => (msg, str.pos.line, str.pos.column)
    }
    return tmp
  }
}
